#include "RenderStage.h"
#include "..\nodes\Node.h"
#include "Renderer.h"
#include "..\content\Material.h"
#include <algorithm>
#include "..\content\ResManager.h"
#include "..\base\Engine.h"
#include "..\game\World.h"

namespace ds {

bool alphaSortFunction(Node* p1,Node* p2) { 
	return p1->getPosition().z < p2->getPosition().z;
}

bool alphaNodeSort(Node* p1,Node* p2) { 
	return p1->getPosition().z < p2->getPosition().z;
}

void BaseRenderStage::renderNode(Renderer* renderer,Node* node) {
	ResourceHandle rh = node->getMaterialHandle();
	Material* m = gEngine->getResourceManager().getMaterial(rh);
	if ( m != 0 ) {		
		//renderer->setRenderState( D3DRS_LIGHTING,false);//m->lightEnabled());			
		renderer->applyTransformation(node);
		node->prepareRendering();
		m->Use();
		if ( m->hasTextures() && !m->hasShaders() ) {
			m->applyTextures();		
		}
		else {
			IDirect3DDevice9 * pDevice = gEngine->getDevice();
			for ( size_t i = 0; i < 5; ++i ) {
				HR(pDevice->SetTexture( i,NULL));					
			}
		}
		if ( m->hasShaders() ) {
			int used = 0;
			uint32 counter = m->getShaderCounter();
			for ( uint32 si = 0; si < counter; ++si ) {
				//Shader* s = m->getShader(si);
				ResourceHandle shaderHandle = m->getShaderHandle(si);
				Shader& s = gEngine->getResourceManager().getShader(shaderHandle);
				if ( s.isActive() ) {
					s.setTechnique();
					// update parameters
					UINT numPasses = 0;
					HR(s.getFX()->Begin(&numPasses,0));
					for ( UINT p = 0; p < numPasses; ++p ) {
						++used;
						HR(s.getFX()->BeginPass(p));
						node->draw();
						HR(s.getFX()->EndPass());
					}
					HR(s.getFX()->End());
				}
			}
			// no shader used then just draw it
			if ( used == 0 ) {
				node->draw();
			}
		}
		// no shaders so simply draw it
		else {
			node->draw();	
		}
		node->postRendering();
	}
	else {
		node->draw();	
	}

}

void AlphaRenderStage::render(Renderer* renderer,List<Node*>& list,bool rtOnly) {	
	if ( list.num() > 0 ) {
		//std::sort(list.begin(),list.end(),alphaNodeSort);
		renderer->setRenderState(D3DRS_ALPHABLENDENABLE,true);
		renderer->setRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
		//renderer->setRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
		renderer->setRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
		
		for ( size_t i = 0; i < list.num(); ++i ) {
			ResourceHandle rh = list[i]->getMaterialHandle();
			Material* m = gEngine->getResourceManager().getMaterial(rh);
			if ( m != 0 && m->hasAlpha() && !list[i]->isOrthogonal() ) {				
				renderNode(renderer,list[i]);
			}
		}
		renderer->setRenderState(D3DRS_ALPHABLENDENABLE,false);
	}
}

void OrthogonalRenderStage::render(Renderer* renderer,List<Node*>& list,bool rtOnly) {		
	if ( list.num() > 0 ) {
		renderer->set2DCameraOn();

		renderer->setRenderState(D3DRS_ALPHABLENDENABLE,true);
		renderer->setRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
		//renderer->setRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
		renderer->setRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);

		for ( size_t i = 0; i < list.num(); ++i ) {
			if ( list[i]->isOrthogonal() ) {
				renderNode(renderer,list[i]);			
			}
		}	
		
		renderer->setRenderState(D3DRS_ALPHABLENDENABLE,false);
		renderer->set2DCameraOff();
	}		
}

void GeometryRenderStage::render(Renderer* renderer,List<Node*>& list,bool rtOnly) {		
	for ( size_t i = 0; i < list.num(); ++i ) {
		ResourceHandle rh = list[i]->getMaterialHandle();
		Material* m = gEngine->getResourceManager().getMaterial(rh);
		if ( m != 0 && !m->hasAlpha() && !list[i]->isOrthogonal() ) {				
			renderNode(renderer,list[i]);
		}
	}
}

void BackgroundRenderStage::render(Renderer* renderer,List<Node*>& list,bool rtOnly) {	
	// FIXME: check mode of layer!
	for ( size_t i = 0; i < list.num(); ++i ) {
		/*
		renderer->set2DCameraOn();
		ResourceHandle rh = list[i]->getMaterialHandle();
		Material* m = gEngine->resourceManager->getMaterial(rh);
		if ( m != 0 && !m->hasAlpha() ) {					
			renderNode(renderer,(Node*)i->get());
		}	
		renderer->set2DCameraOff();
		*/
	}		
}

};
